﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reactive.Linq;

using SomeKit.Rx.Http;
using SomeKit.Serialization;

namespace SomeKit.Rx.TypeSafe
{
    public static partial class ClientHelper
    {
        /// <summary>
        /// Prepares a IObservable that will execute the "POST" verb against the resource located at <paramref name="uri"/>.
        /// </summary>
        /// <typeparam name="BODY">A type of object to be sent to the server.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="body">The body of the request.</param>
        /// <typeparam name="BODY">A type of object to be sent to the server.</typeparam>
        /// <param name="serializer">A method that is capable of serializing <paramref name="body"/>.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<string> Post<BODY>(this Uri uri, BODY body, Func<BODY, string> serializer, Action<HttpWebRequest> headerHandler = null)
        {
            return uri.Post(serializer(body), headerHandler);
        }

        /// <summary>
        /// Executes the "POST" verb against the resource located at <paramref name="uri"/>. The request body is expected to be formatted in XML.
        /// </summary>
        /// <typeparam name="BODY">A type of object to be sent to the server.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="body">The body of the request.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<string> PostXml<BODY>(this Uri uri, BODY body, Action<HttpWebRequest> headerHandler = null)
        {
            return uri.PostXml(body.SerializeXml(), headerHandler);
        }

        /// <summary>
        /// Executes the "POST" verb against the resource located at <paramref name="uri"/>. The request body is expected to be formatted in JSON.
        /// </summary>
        /// <typeparam name="BODY">A type of object to be sent to the server.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="body">The body of the request.</param>
        /// <param name="errorHandler">The error handler.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<string> PostJson<BODY>(this Uri uri, BODY body, Action<HttpWebRequest> headerHandler = null)
        {
            return uri.PostJson(body.SerializeJson(), headerHandler);
        }


        /// <summary>
        /// Executes the "POST" verb against the resource located at <paramref name="uri"/>.
        /// </summary>
        /// <typeparam name="RESULT">The type of the result parameter.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="handler">The handler receiving the resultant object.</param>
        /// <param name="errorHandler">The error handler.</param>
        /// <param name="deserializer">A method capable of deserializing the resultant object.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<RESULT> Post<RESULT>(this Uri uri, Func<string, RESULT> deserializer, Action<HttpWebRequest> headerHandler = null)
        {
            var obs = uri.Post(headerHandler);
            return obs.Select(s => deserializer(s));
        }
        /// <summary>
        /// Executes the "POST" verb against the resource located at <paramref name="uri"/>. The request body is expected to be formatted in XML.
        /// </summary>
        /// <typeparam name="RESULT">The type of the result parameter.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<RESULT> PostXml<RESULT>(this Uri uri, Action<HttpWebRequest> headerHandler = null)
        {
            var obs = uri.PostXml(headerHandler);
            return obs.Select(s => s.DeserializeXml<RESULT>());
        }
        /// <summary>
        /// Executes the "POST" verb against the resource located at <paramref name="uri"/>. The request body is expected to be formatted in JSON.
        /// </summary>
        /// <typeparam name="RESULT">The type of the result parameter.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<RESULT> PostJson<RESULT>(this Uri uri, Action<RESULT> handler, Action<Exception> errorHandler, Action<HttpWebRequest> headerHandler = null)
        {
            var obs = uri.PostJson(headerHandler);
            return obs.Select(s => s.DeserializeXml<RESULT>());
        }

        /// <summary>
        /// Executes the "POST" verb against the resource located at <paramref name="uri"/>.
        /// </summary>
        /// <typeparam name="BODY">A type of object to be sent to the server.</typeparam>
        /// <typeparam name="RESULT">The type of the result parameter.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="body">The body of the request.</param>
        /// <param name="handler">The handler receiving the resultant object.</param>
        /// <param name="errorHandler">The error handler.</param>
        /// <param name="serializer">A method that is capable of serializing <paramref name="body"/>.</param>
        /// <param name="deserializer">A method capable of deserializing the resultant object.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<RESULT> Post<BODY, RESULT>(this Uri uri, BODY body, Func<BODY, string> serializer, Func<string, RESULT> deserializer, Action<HttpWebRequest> headerHandler = null)
        {
            var obs = uri.Post(serializer(body), headerHandler);
            return obs.Select(s=>deserializer(s));
        }
        /// <summary>
        /// Executes the "POST" verb against the resource located at <paramref name="uri"/>. The request body is expected to be formatted in XML.
        /// </summary>
        /// <typeparam name="BODY">A type of object to be sent to the server.</typeparam>
        /// <typeparam name="RESULT">The type of the result parameter.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="body">The body of the request.</param>
        /// <param name="handler">The handler receiving the resultant object.</param>
        /// <param name="errorHandler">The error handler.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<RESULT> PostXml<BODY, RESULT>(this Uri uri, BODY body, Action<HttpWebRequest> headerHandler = null)
        {
            var obs = uri.PostXml(body.SerializeXml(), headerHandler);
            return obs.Select(s=>s.DeserializeXml<RESULT>());
        }
        /// <summary>
        /// Executes the "POST" verb against the resource located at <paramref name="uri"/>. The request body is expected to be formatted in JSON.
        /// </summary>
        /// <typeparam name="BODY">A type of object to be sent to the server.</typeparam>
        /// <typeparam name="RESULT">The type of the result parameter.</typeparam>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="body">The body of the request.</param>
        /// <param name="headerHandler">Custom header handler.</param>
        public static IObservable<RESULT> PostJson<BODY, RESULT>(this Uri uri, BODY body, Action<RESULT> handler, Action<Exception> errorHandler, Action<HttpWebRequest> headerHandler = null)
        {
            var obs = uri.PostJson(body.SerializeJson(),headerHandler);
            return obs.Select(s=>s.DeserializeJson<RESULT>());
        }
    }
}
